package cn.edu.nwpu.warehousemanagement.dao;

import cn.edu.nwpu.warehousemanagement.constantEnum.FreightStatus;
import cn.edu.nwpu.warehousemanagement.pojo.Freight;
import cn.edu.nwpu.warehousemanagement.pojo.Product;
import cn.edu.nwpu.warehousemanagement.pojo.Shelf;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

@Repository
public interface FreightRepository extends JpaRepository<Freight, Long> {

    // ==================== 基础CRUD ====================
    // 继承自JpaRepository:
    // save()               - 创建/更新货物
    // findById()           - 根据ID查询
    // deleteById()         - 根据ID删除(软删除)
    // findAll()            - 查询所有未删除的货物

    //精确匹配ID
    Optional<Freight> findByIdAndDeletedFalse(Long id);

    // 查询包括已删除的记录
    @Query("SELECT f FROM Freight f WHERE f.id = :id")
    Optional<Freight> findByIdIncludeDeleted(@Param("id") Long id);

    // 查询所有记录（包括已删除的）
    @Query("SELECT f FROM Freight f")
    List<Freight> findAllIncludeDeleted();

    // 物理删除
    @Modifying
    @Transactional
    @Query("DELETE FROM Freight f WHERE f.id = :id")
    void hardDeleteById(@Param("id") Long id);

    // ==================== 按商品查询 ====================
    // 查询指定商品的所有未删除货物
    List<Freight> findByProductAndDeletedFalse(Product product);

    // 查询指定商品ID的所有未删除货物
    List<Freight> findByProductIdAndDeletedFalse(Long productId);

    // 查询多个商品的未删除货物
    List<Freight> findByProductIdInAndDeletedFalse(List<Long> productIds);

    // ==================== 按货架查询 ====================
    // 查询指定货架上的所有未删除货物
    List<Freight> findByShelfAndDeletedFalse(Shelf shelf);

    // 查询指定货架ID的所有未删除货物
    List<Freight> findByShelfIdAndDeletedFalse(Long shelfId);

    // 查询货架上的特定状态未删除货物
    List<Freight> findByShelfIdAndStatusAndDeletedFalse(Long shelfId, FreightStatus status);

    // ==================== 按状态查询 ====================
    // 查询指定状态的所有未删除货物
    List<Freight> findByStatusAndDeletedFalse(FreightStatus status);

    // 查询非指定状态的未删除货物
    List<Freight> findByStatusNotAndDeletedFalse(FreightStatus status);

    // ==================== 按日期查询 ====================
    // 查询生产日期在指定日期之后的未删除货物
    List<Freight> findByProductionDateAfterAndDeletedFalse(LocalDate date);

    // 查询过期日期在指定日期之前的未删除货物（临期/过期货物）
    List<Freight> findByExpirationDateBeforeAndDeletedFalse(LocalDate date);

    // 查询有效期内的未删除货物（未过期）
    @Query("SELECT f FROM Freight f WHERE f.expirationDate >= CURRENT_DATE AND f.deleted = false")
    List<Freight> findValidFreights();

    // 查询指定日期范围内的未删除入库货物
    List<Freight> findByInboundTimeBetweenAndDeletedFalse(LocalDateTime start, LocalDateTime end);

    /**
     * 根据ID列表查询多个未删除的货物
     * @param ids 货物ID列表
     * @return 匹配的货物列表
     */
    List<Freight> findByIdInAndDeletedFalse(List<Long> ids);

    // ==================== 组合查询 ====================
    // 查询特定商品且状态可用的未删除货物
    List<Freight> findByProductIdAndStatusAndDeletedFalse(Long productId, FreightStatus status);

    // 查询特定货架上的临期商品（30天内过期）未删除货物
    @Query("SELECT f FROM Freight f WHERE f.shelf.id = :shelfId " +
            "AND f.expirationDate BETWEEN CURRENT_DATE AND :expireDate " +
            "AND f.deleted = false")
    List<Freight> findExpiringFreightsOnShelf(
            @Param("shelfId") Long shelfId,
            @Param("expireDate") LocalDate expireDate);

    // ==================== 库存操作 ====================
    // 批量更新未删除货物状态
    @Modifying
    @Transactional
    @Query("UPDATE Freight f SET f.status = :status WHERE f.id IN :ids AND f.deleted = false")
    void batchUpdateStatus(
            @Param("ids") List<Long> ids,
            @Param("status") FreightStatus status);

    // 转移未删除货物到新货架
    @Modifying
    @Transactional
    @Query("UPDATE Freight f SET f.shelf.id = :newShelfId WHERE f.id = :freightId AND f.deleted = false")
    int relocateFreight(
            @Param("freightId") Long freightId,
            @Param("newShelfId") Long newShelfId);

    // 软删除货物
    @Modifying
    @Transactional
    @Query("UPDATE Freight f SET f.deleted = true WHERE f.id = :id")
    int softDeleteById(@Param("id") Long id);

    // 批量软删除
    @Modifying
    @Transactional
    @Query("UPDATE Freight f SET f.deleted = true WHERE f.id IN :ids")
    int batchSoftDelete(@Param("ids") List<Long> ids);

    // 恢复软删除的货物
    @Modifying
    @Transactional
    @Query("UPDATE Freight f SET f.deleted = false WHERE f.id = :id")
    int restoreById(@Param("id") Long id);

    // ==================== 统计查询 ====================
    // 统计货架上的未删除货物数量
    long countByShelfIdAndDeletedFalse(Long shelfId);

    // 统计商品的不同状态未删除货物数量
    @Query("SELECT f.status, COUNT(f) FROM Freight f WHERE f.product.id = :productId AND f.deleted = false GROUP BY f.status")
    List<Object[]> countByProductIdGroupByStatus(@Param("productId") Long productId);

    // 检查货架是否为空（只统计未删除的）
    default boolean isShelfEmpty(Long shelfId) {
        return countByShelfIdAndDeletedFalse(shelfId) == 0;
    }

    // ==================== 业务逻辑查询 ====================
    // 获取最早入库的可用未删除货物（FIFO策略）
    @Query("SELECT f FROM Freight f WHERE f.product.id = :productId AND f.status = 'IN_STOCK' AND f.deleted = false " +
            "ORDER BY f.inboundTime ASC LIMIT 1")
    Optional<Freight> findEarliestAvailableByProductId(@Param("productId") Long productId);

    // 查询需要质量检查的未删除货物（入库超过30天未检查）
    @Query("SELECT f FROM Freight f WHERE f.status = 'IN_STOCK' AND f.deleted = false " +
            "AND f.inboundTime < :checkDate")
    List<Freight> findFreightsNeedInspection(
            @Param("checkDate") LocalDateTime checkDate);


    // ==================== 新增的分页查询 ====================
    Page<Freight> findAllByDeletedFalse(Pageable pageable);

    Page<Freight> findByStatusAndDeletedFalse(FreightStatus status, Pageable pageable);

    Page<Freight> findByProductNameContainingAndDeletedFalse(String productName, Pageable pageable);

    // ==================== 新增的非分页查询 ====================
    List<Freight> findByProductNameContainingAndDeletedFalse(String productName);


    // 根据货架ID和状态查询未删除的在库货物（分页）
    Page<Freight> findByShelfIdAndStatusAndDeletedFalse(Long shelfId, FreightStatus status, Pageable pageable);


    // 分页查询：根据产品名称模糊搜索在库商品
    @Query("SELECT f FROM Freight f " +
            "JOIN f.product p " + // 关联Product实体
            "WHERE p.name LIKE %:productName% " + // 产品名称模糊匹配
            "AND f.status = 'IN_STOCK' " + // 状态为在库
            "AND f.deleted = false") // 未删除
    Page<Freight> findByProductNameContainingAndInStock(
            @Param("productName") String productName,
            Pageable pageable);

    /**
     * 根据产品名称模糊搜索出库商品（OUT_STOCK状态）
     * @param productName 产品名称（模糊匹配）
     * @param pageable 分页参数
     * @return 分页的出库商品列表
     */
    @Query("SELECT f FROM Freight f " +
            "JOIN f.product p " + // 关联Product实体
            "WHERE p.name LIKE %:productName% " + // 产品名称模糊匹配
            "AND f.status = 'SHIPPED' " + // 状态为出库
            "AND f.deleted = false") // 未删除
    Page<Freight> findByProductNameContainingAndOutStock(
            @Param("productName") String productName,
            Pageable pageable);


    /**
     * 根据货架、状态、ProductName分页查询
     * @param shelfId 货架ID
     * @param status Freight状态
     * @param productName 商品名称
     * @param pageable 分页参数
     * @return 分页的Freight列表
     */
    @Query("SELECT f FROM Freight f " +
            "JOIN f.product p " +
            "WHERE f.shelf.id = :shelfId " +
            "AND f.status = :status " +
            "AND p.name LIKE %:productName% " +
            "AND f.deleted = false")
    Page<Freight> findFreightsByShelfAndStatusAndProductName(
            @Param("shelfId") Long shelfId,
            @Param("status") FreightStatus status,
            @Param("productName") String productName,
            Pageable pageable);

    //查找指定Product关联的非FreightStatus状态且未删除的Freight 如查找指定Product关联的非SHIPPED状态且未删除的Freight
    List<Freight> findByProductIdAndStatusNotAndDeletedFalse(Long productId, FreightStatus status);

}